#!/usr/bin/env node
require('PhoenixNirvana');

const
	readlineSync = require('readline-sync'),
	EventEmitter = require('events'),
	fs = require('fs'),
	qs = require('querystring'),
	path = require('path'),
	colors = require('colors'),
	ansi = require('ansi'),
	esprintf = require('esprintf'),
	util = require('util');

const
	cursor = ansi(process.stdout);

process.on('uncaughtException', function (err) {
	console.log('Caught exception: ' + err);
});

function parseCl(cl) {
	var reToken = new RegExp(/(\s*)(?:("|')(.*?)(?:\2|$)|(\S+))/g), matches,
		taken = '', args = [], part;
		cl = cl.trim();
	while ((matches = reToken.exec(cl))) {
		part = matches[3] || matches[4] || '';
		if (matches[1]) {
			args.push(taken);
			taken = '';
		}
		taken += part;
	}
	if (taken) { args.push(taken); }
	return args;
}
var ep = new EventEmitter();

class Console {
	options = {prompt: '# '};
	readOptions = {prompt: this.options.prompt};
	_targets = [];
	_webshells = [];
	constructor(){
		console.log('Attack with Defence Framework');
	}
	get target(){
		return this._targets;
	}
	get webshell(){
		return this._webshells;
	}
	prompt(){
		this.readOptions.prompt = this.options.prompt;
	}
	async help(){
		[
			['help|h', '帮助'],
			['quit|q', '退出控制台'],
			['module|mod|m [module name]', '选择指定模块，未指定模块名称则显示所有模块'],
			['controller|con|c [controller name]', '选择指定控制器，未指定控制器名称则显示所有控制器'],
			['action|act|a [action name]', '选择指定动作，未指定动作名称则显示所有动作'],
			['run|r', '执行动作'],
			['exit|..', '返回上一级'],
			['options|o', '查看参数'],
			['set <key> <value>', '设置变量值'],
			['unset <key>', '删除变量'],
			['cache', '查看缓冲区变量'],
			['cache get <key>', '获取缓冲变量'],
			['cache set <key> <value>', '存储到缓冲'],
			['cache unset <key>', '删除缓冲变量'],
			['<module>:', '直达指定模块'],
			['<module>:<controller>', '直达指定控制器'],
			['<module>:<controller>/<action>', '直达指定动作'],
			['payload|p <module>:<controller>', '加载payload'],
		].map(item => {
			console.log(esprintf('%-40s %s', item[0], item[1]));
		})
	}
	start(){
		ep.on('prompt',async () => {
			let input = readlineSync.prompt(this.readOptions).trim();
			let args = parseCl(input);
			if (args.length == 0) {
				ep.emit('prompt');
				return;
			}
			let r;
			switch(args[0]){
				case 'exit':
					process.exit();
					break;
				case 'h':
				case 'help':
					await this.help(args.slice(1));
					break;
				default:
					console.log(`Unknown command: ${args[0]}`);
					break;
			}
			ep.emit('prompt'); // loop
		})
		ep.emit('prompt'); // first
	}
}

let _console = new Console();
_console.start();
